package session.stateful;

import entity.AddressEntity;
import entity.BranchEntity;
import entity.FnBBranchEntity;
import entity.FnBIOTREntity;
import entity.PackagePurchasedEntity;
import entity.ServicePackageEntity;
import entity.StakeholderEntity;
import java.util.Date;
import java.util.List;
import javax.ejb.LocalBean;
import javax.ejb.Stateful;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import util.exception.ChangeServicePackageException;
import util.exception.ExtendServicePackageException;
import util.exception.TerminateServicePackageException;

@Stateful
@LocalBean
public class BranchSessionBean {

    private static String TRIAL = "Trial Package";
    private static int MONTHOFTRIAL = 1;
    @PersistenceContext
    private EntityManager entityManager;

    public List<BranchEntity> getAllBranchByStakeholderId(Long stakeholderId) {
        StakeholderEntity stakeholder = entityManager.find(StakeholderEntity.class, stakeholderId);
        return stakeholder.getBranch();
    }
    
    public List<BranchEntity> getAllBranch() {
        Query query = entityManager.createQuery("SELECT b FROM BranchEntity b");
        return query.getResultList();
    }

    public void editBranchInfo(FnBBranchEntity branch) {
        entityManager.merge(branch.getFnBIOTR());
        entityManager.merge(branch);
    }

    private Date getNextExpiredDate(int billingDay, Date date) {
        if (billingDay <= date.getDate()) {
            Date tempDate = new Date(date.getYear(), date.getMonth(), billingDay);
            return getExpiredDate(tempDate, 1);
        }

        int maxDay = getMaxDayOfMonth(date.getMonth(), date.getYear());
        Date tempDate = new Date(date.getYear(), date.getMonth(), Math.min(billingDay, maxDay));
        return tempDate;
    }

    private int getMaxDayOfMonth(int month, int year) {
        switch (month) {
            case 0:
            case 2:
            case 4:
            case 6:
            case 7:
            case 9:
            case 11:
                return 31;
            case 1:
                if (isLeapYear(year)) {
                    return 29;
                } else {
                    return 28;
                }
            default:
                return 30;
        }
    }

    public void buyNewPackage(long branchId, Date datePurchased, long selectedServicePackageId, int numOfMonth) throws ChangeServicePackageException {
        BranchEntity branch = entityManager.find(BranchEntity.class, branchId);
        ServicePackageEntity selectedServicePackage = entityManager.find(ServicePackageEntity.class, selectedServicePackageId);

        if (!selectedServicePackage.isVisibility()) {
            throw new ChangeServicePackageException("This service package is not offering now! So you can't buy it");
        }

        PackagePurchasedEntity pack = new PackagePurchasedEntity();

        Date dateExpired = getExpiredDate(datePurchased, numOfMonth);

        pack.setPrice(selectedServicePackage.getPrice());
        pack.setDateExpired(dateExpired);
        pack.setDatePurchased(datePurchased);
        pack.setBranch(branch);
        pack.setServicePackage(selectedServicePackage);

        entityManager.persist(pack);
        selectedServicePackage.getPackagePurchased().add(pack);

        branch.getPackagePurchased().add(pack);
    }

    private int getCurrentPackage(List<PackagePurchasedEntity> tempList) {
        Date date = new Date();
        int pos = 0;
        //find the current package that this branch is using now
        for (; pos < tempList.size(); pos++) {
            if (tempList.get(pos).getDatePurchased().compareTo(date) <= 0
                    && tempList.get(pos).getDateExpired().compareTo(date) > 0) {
                return pos;
            }
        }
        return -1;
    }

    private void deleteRedundantPackagePurchased(int pos, List<PackagePurchasedEntity> tempList) {
        while (pos != tempList.size() - 1) {
            PackagePurchasedEntity temp = tempList.get(tempList.size() - 1);

            temp.getServicePackage().getPackagePurchased().remove(temp);
            tempList.remove(temp);

            entityManager.remove(temp);
        }
    }

    public void extendCurrentPackage(long branchId, int numOfMonth) throws ExtendServicePackageException {
        BranchEntity branch = entityManager.find(BranchEntity.class, branchId);
        List<PackagePurchasedEntity> tempList = branch.getPackagePurchased();

        if (!tempList.isEmpty()) {
            int pos = getCurrentPackage(tempList);
            PackagePurchasedEntity currentPackage = tempList.get(pos);

            if (!currentPackage.getServicePackage().isVisibility()) {
                throw new ExtendServicePackageException("This service package is not offering now! So you can't extend it");
            }

            deleteRedundantPackagePurchased(pos, tempList);

            ServicePackageEntity sp = currentPackage.getServicePackage();
            if (currentPackage.getPrice() == sp.getPrice()) {
                currentPackage.setDateExpired(getExpiredDate(currentPackage.getDateExpired(), numOfMonth));
                entityManager.merge(currentPackage);
            } else {
                PackagePurchasedEntity newPackage = new PackagePurchasedEntity();
                newPackage.setServicePackage(sp);

                Date newDate = currentPackage.getDateExpired();

                newPackage.setDatePurchased(newDate);
                newPackage.setDateExpired(getExpiredDate(newDate, numOfMonth));
                newPackage.setPrice(sp.getPrice());

                entityManager.persist(newPackage);
                tempList.add(newPackage);
            }
        } else {
            throw new ExtendServicePackageException("You don't have any valid service package yet.");
        }
        entityManager.merge(branch);
    }

    public void terminateCurrentPackage(long branchId) throws TerminateServicePackageException {
        BranchEntity branch = entityManager.find(BranchEntity.class, branchId);
        List<PackagePurchasedEntity> tempList = branch.getPackagePurchased();

        if (!tempList.isEmpty()) {
            int pos = getCurrentPackage(tempList);
            PackagePurchasedEntity currentPackage = tempList.get(pos);

            deleteRedundantPackagePurchased(pos, tempList);

            Date date = new Date();
            int billingDay = branch.getBillingDay();

            int newDate = Math.min(billingDay, getMaxDayOfMonth(date.getMonth(), date.getYear()));
            Date newExpiredDate = new Date(date.getYear(), date.getMonth(), newDate);
            if (date.getDate() >= billingDay) {
                newExpiredDate = getExpiredDate(newExpiredDate, 1);
            }

            currentPackage.setDateExpired(newExpiredDate);
        } else {
            throw new TerminateServicePackageException("You don't have any service package to terminate");
        }
    }

    public void changeCurrentPackage(long branchId, long selectedServicePackageId, int numOfMonth) throws ChangeServicePackageException {
        BranchEntity branch = entityManager.find(BranchEntity.class, branchId);
        List<PackagePurchasedEntity> list = branch.getPackagePurchased();
        int pos = getCurrentPackage(list);
        ServicePackageEntity selectedServicePackage = entityManager.find(ServicePackageEntity.class, selectedServicePackageId);

        if (pos != - 1 && selectedServicePackage.equals(list.get(pos).getServicePackage())) {
            throw new ChangeServicePackageException("You must change to another service package");
        }


        try {
            terminateCurrentPackage(branchId);
        } catch (TerminateServicePackageException ex) {
        }

        Date beginDateOfNewPackage = new Date();
        if (pos != - 1) {
            beginDateOfNewPackage = list.get(pos).getDateExpired();
        }
        buyNewPackage(branchId, beginDateOfNewPackage, selectedServicePackageId, numOfMonth);
    }

    public PackagePurchasedEntity getCurrentPackagePurchased(Long branchId) {
        BranchEntity branch = entityManager.find(BranchEntity.class, branchId);

        List<PackagePurchasedEntity> list = branch.getPackagePurchased();
        int pos = getCurrentPackage(list);

        if (pos != - 1) {
            return list.get(pos);
        }

        return null;
    }

    public void createNewBranch(StakeholderEntity selectedStakeholder, FnBBranchEntity selectedBranch, AddressEntity address, FnBIOTREntity fnBIOTR) {
        try {
            Date dateCreated = new Date();

            entityManager.persist(address);
            entityManager.persist(selectedBranch);
            entityManager.persist(fnBIOTR);

            selectedBranch.setBillingDay(dateCreated.getDate());
            selectedBranch.setStakeholder(selectedStakeholder);
            selectedBranch.setBranchAddress(address);

            selectedStakeholder.getBranch().add(selectedBranch);
            selectedBranch.setFnBIOTR(fnBIOTR);
            fnBIOTR.setFnBBranch(selectedBranch);
            entityManager.merge(selectedStakeholder);
            /*
            Query query = entityManager.createQuery("SELECT s FROM ServicePackage s WHERE s.name LIKE :name");
            query.setParameter("name", TRIAL);
            ServicePackage sp = (ServicePackage) query.getSingleResult();
            System.out.println(sp.getName());
             */
            //Date dateExpired = getExpiredDate(dateCreated, MONTHOFTRIAL);

            //editPackagePurchased(tempBranch, sp, dateCreated, dateExpired);

        } catch (Exception ex) {
        }
    }

    private Date getExpiredDate(Date dateCreated, int numOfMonth) {
        int prevMonth = dateCreated.getMonth();
        int prevYear = dateCreated.getYear();
        int prevDate = dateCreated.getDate();
        int nextMonth, nextDate, nextYear;

        nextMonth = (prevMonth + numOfMonth) % 12;
        nextYear = prevYear + (prevMonth + numOfMonth) / 12;

        if (prevDate <= 28) {
            nextDate = prevDate;
        } else if (nextMonth == 1) {
            if (isLeapYear(nextYear)) {
                nextDate = 29;
            } else {
                nextDate = 28;
            }
        } else if (nextMonth == 3 || nextMonth == 5 || nextMonth == 9 || nextMonth == 10) {
            nextDate = Math.min(30, prevDate);
        } else {
            nextDate = Math.min(31, prevDate);
        }

        return new Date(nextYear, nextMonth, nextDate);
    }

    private boolean isLeapYear(int year) {
        if (year % 400 == 0) {
            return true;
        }
        if (year % 100 == 0) {
            return false;
        }
        if (year % 4 == 0) {
            return true;
        }
        return false;
    }

    public PackagePurchasedEntity getLatestPackagedPurchasedByBranchId(Long id) {
        BranchEntity branch = entityManager.find(BranchEntity.class, id);
        List<PackagePurchasedEntity> list = branch.getPackagePurchased();

        PackagePurchasedEntity packagePurchased = new PackagePurchasedEntity();
        if (!list.isEmpty()) {
            packagePurchased = list.get(list.size() - 1);
        }
        return packagePurchased;
    }
}
